﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Runtime.Remoting.Contexts;
using System.Security.Policy;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;

namespace PhoneNumber.Classes
{
    internal class Crawlers
    {
        private string thisUrl="";
        private List<Thread> threads; //父线程传递的公共线程容器
        private HashSet<string> tableUrl; //父线程传递的已读取URL列表
        private HashSet<string> tablePhone; //父线程传递的已读取电话号码列表
        private Semaphore semaphore; //父线程传递的信号量成员
        private CancellationToken token; //管理线程的标志量
        private List<string> urlScanned=new List<string>(); //本对象爬取页面找到的URL
        private List<string> phoneNumberScanned=new List<string>(); //本对象爬取页面找到的电话号码
        string webContent = ""; //网页内容
        MessageSender sender=new MessageSender(); //提供windows消息传递方法

        public Crawlers(List<Thread>threads, HashSet<string> tableUrl, HashSet<string> tablePhone)
        {
            this.tablePhone = tablePhone;
            this.tableUrl = tableUrl;
            this.threads = threads;
        }

        public Crawlers(List<Thread> threads, HashSet<string> tableUrl, HashSet<string> tablePhone, 
            Semaphore semaphore, CancellationToken token)
        {
            this.tablePhone = tablePhone;
            this.tableUrl = tableUrl;
            this.threads = threads;
            this.semaphore = semaphore;
            this.token = token;
        }

        /// <summary>
        /// 启动线程后的功能实现方法
        /// </summary>
        /// <param name="url"></param>
        public void Scan(string url)
        {
            if (token.IsCancellationRequested) return;
            if (semaphore != null)
                semaphore.WaitOne();
            thisUrl = url;
            GetHttp(url);
            _scan(webContent);
            Thread.Sleep(2048);
            NewUrlScanned(webContent);
            if (semaphore != null)
                semaphore.Release();
        }

        /// <summary>
        /// 获取某url的web文本，传输到类成员webContext中
        /// </summary>
        /// <param name="url"></param>
        private void GetHttp(string url)
        {
            webContent = "";
            if (token.IsCancellationRequested) return;
            try
            {
                HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
                request.Method = "GET";
                request.Proxy = null;
                HttpWebResponse response = (HttpWebResponse)request.GetResponse();
                using (Stream stream = response.GetResponseStream())
                {
                    using (StreamReader reader = new StreamReader(stream))
                    {
                        webContent = reader.ReadToEnd();
                    }
                }
            } catch (Exception exp)
            {
                webContent = exp.Message;
            }
        }

        /// <summary>
        /// 扫描web文本内容，将新的url和电话号码添加到类的List容器中
        /// </summary>
        /// <param name="content">web文本的内容</param>
        private void _scan(string content) { 
            //System.Console.WriteLine("------------------------------------------");
            //Regex regexUrl = new Regex(@"[a-zA-z]+://[^\s]*"); //Regex regexUrl = new Regex(@"[https|http]+://[^\s'-]*");
            Regex regexUrl = new Regex("[https|http]+://[^\"'）)-]*");
            //电话号码(“XXX-XXXXXXX”、”XXXX-XXXXXXXX”、”XXX-XXXXXXXX”)
            Regex regexPhone = new Regex("[0-9]{3,4}-[0-9]{7,8}");
            MatchCollection collectionUrl = regexUrl.Matches(content);
            MatchCollection collectionPhone = regexPhone.Matches(content);
            foreach(var item in collectionPhone)
            {
                Thread.Sleep(150);
                if (token.IsCancellationRequested) 
                    return;
                if (tablePhone.Contains(item.ToString()))
                    continue;
                sender.StartSendMessage("FormGetPhoneNumber", "phone: " + item.ToString() + ",\turl: " + thisUrl);
                phoneNumberScanned.Add(item.ToString());
                tablePhone.Add(item.ToString());
            }
            foreach (var item in collectionUrl)
            {
                Thread.Sleep(150);
                if (token.IsCancellationRequested) 
                    return;
                if (tableUrl.Contains(item.ToString()))
                    continue;
                sender.StartSendMessage("FormGetPhoneNumber", "url scanned: " + item.ToString());
                urlScanned.Add(item.ToString());
                tableUrl.Add(item.ToString());
                //System.Console.WriteLine(item.ToString());
            }
        }

        /// <summary>
        /// 将扫描到的url包装到一个新的爬虫类对象中，并启动爬虫对象的线程
        /// </summary>
        /// <param name="content">web文本的内容</param>
        private void NewUrlScanned(string content)
        {
            foreach(string _url in urlScanned)
            {
                if(token.IsCancellationRequested) 
                    return;
                Thread.Sleep(150);
                Thread thread = new Thread(() =>
                {
                    //new Crawlers(threads, tableUrl, tablePhone).Scan(_url);
                    new Crawlers(threads, tableUrl, tablePhone,
                        semaphore, token).Scan(_url);
                });
                threads.Add(thread);
                thread.Start();
            }
        }
    }
}
